$(function () {
	// 初始化地图
	var map = new Map("map");
	// 初始化全景图浏览器
	var pano = new Pano("panoContainer");
	// 存储从后端获取的多段线
	var polylines;
	// 缓存从后端获取的多段线的照片
	var pictures = {};
	// 存储当前的多段线
	var currentPolyline;
	// 存储当前的全景图
	var currentPicture;
	// 获取并加载多段线
	$.ajax("/api/polylines").done(function (value) {
		polylines = JSON.parse(value);
		map.render(polylines);
	});
	// 监听用户点击多段线事件
	map.on("click", function (e) {
		// 切换到全景图模式
		if (map.reduce()) {
			// 地图缩放到被点击的多段线
			if (map.getZoom() < 13)
				map.fit(e.polyline);
			else
				setTimeout(map.zoomAroundMarker, 200);
			// 显示全景图浏览器
			pano.show();
			// 显示后退按钮
			$(".icon").removeClass("hide");
		}
		currentPolyline = e.polyline;
		// 获取被点击的多段线的照片
		if (pictures[e.polyline.id]) {
			currentPicture = closestPoint(e.latlng, pictures[e.polyline.id]);
			map.showMarker(currentPicture.latitude, currentPicture.longitude);
			pano.render(currentPicture.fileName.substr(1), currentPicture.next != null, currentPicture.previous != null);
		} else {
			$.ajax("/api/polylines/" + e.polyline.id).done(function (value) {
				var obj = JSON.parse(value);
				// 缓存
				pictures[e.polyline.id] = obj;
				// 搜索离点击位置最近的照片
				currentPicture = closestPoint(e.latlng, obj);
				map.showMarker(currentPicture.latitude, currentPicture.longitude);
				pano.render(currentPicture.fileName.substr(1), currentPicture.next != null, currentPicture.previous != null);
			});
		}
	});
	// 监听用户点击前进箭头事件
	pano.on("forward", function () {
		if (currentPicture.next != null) {
			var picture = pictures[currentPolyline.id].filter(function (value) {
				return value.id === currentPicture.next;
			})[0];
			currentPicture = picture;
			map.showMarker(currentPicture.latitude, currentPicture.longitude);
			pano.render(picture.fileName.substr(1), picture.next != null, picture.previous != null);
		}
	});
	// 监听用户点击后退箭头事件
	pano.on("backward", function () {
		if (currentPicture.previous != null) {
			var picture = pictures[currentPolyline.id].filter(function (value) {
				return value.id === currentPicture.previous;
			})[0];
			currentPicture = picture;
			map.showMarker(currentPicture.latitude, currentPicture.longitude);
			pano.render(picture.fileName.substr(1), picture.next != null, picture.previous != null);
		}
	});
	// 监听用户点击后退按钮事件
	$(".icon").click(function () {
		// 切换到大图模式
		if (map.enlarge()) {
			// 隐藏全景图浏览器
			pano.hide();
			// 隐藏后退按钮
			$(this).addClass("hide");
		}
	});
	// 监听用户点击右上角快捷按钮
	$("li button").click(function () {
		var index1 = $(this).parent().index();
		var index2 = -1;
		switch (index1) {
			case 0: // 高速公路
				index2 = 2;
				break;
			case 1: // 嘉定校区
				index2 = 1;
				break;
			case 2: // 五洲大道
				index2 = 0;
				break;
			default:
				break;
		}
		if (polylines[index2])
			map.fit(polylines[index2]);
	});
});

/*
 * Class Map
 */
var Map = (function () {
	// leaflet 的 L.Map 实例
	var map;
	// 地图所在的 HTMLElement 的父级
	var mapContainer;
	// 事件处理方法集合
	var listeners = {
		"click": []
	};
	// 多段线集合
	var polylines = [];
	// 当前标记
	var marker;
	 
	// 构造函数
	// 参数 element 是渲染地图的 HTMLElement
	var Map = function (element) {
		// 初始化地图
		map = L.map(element, {
			attributionControl: false
		}).setView([31.1, 121.50], 11);
		map.zoomControl.setPosition("bottomright");
		mapContainer = map.getContainer().parentNode;
		// 添加瓦片图层
		var mapTiles = L.layerGroup([
			L.tileLayer(
				"http://{s}.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}", 
				{ 
					attribution: "&copy; <a href='http://www.tianditu.com/map/index.html'>天地图</a>", 
					subdomains: ["t2", "t3", "t4", "t5", "t6"], 
					detectRetina: true, 
					reuseTiles: true,
					zIndex: 0
				}
			), 
			L.tileLayer(
				"http://{s}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}", 
				{ 
					attribution: "&copy; <a href='http://www.tianditu.com/map/index.html'>天地图</a>", 
					subdomains: ["t2", "t3", "t4", "t5", "t6"], 
					detectRetina: true, 
					reuseTiles: true,
					zIndex: 0
				}
			)
		]).addTo(map);
	};
	
	// 渲染多段线
	Map.prototype.render = function (geometries) {
		geometries.forEach(function (value) {
			var geoJson = L.geoJson(JSON.parse(value.geometry));
			geoJson.on("click", function (e) {
				// 用户点击了多段线，触发 click 事件，并将坐标和多段线作为事件数据
			 	fire("click", { 
					latlng: e.latlng,
					polyline: value
				});
			});
			map.addLayer(geoJson);
			polylines.push({
				origin: value,
				layer: geoJson
			});
		});
	};
	
	// 切换到小图模式
	// 如果地图已处于小图模式，返回 false，否则返回 true
	Map.prototype.reduce = function () {
		if ($(mapContainer).hasClass("small"))
			return false;
		else {
			$(mapContainer).addClass("small");
			map.invalidateSize(false);
			return true;
		}
	};
	
	// 切换到大图模式
	// 如果地图已处于大图模式，返回 false，否则返回 true
	Map.prototype.enlarge = function () {
		if ($(mapContainer).hasClass("small")) {
			$(mapContainer).removeClass("small");
			map.invalidateSize(false);
			return true;
		} else
			return false;
	}
	
	// 缩放到指定的多段线
	Map.prototype.fit = function (polyline) {
		map.fitBounds(polylines.filter(function (value) {
			return value.origin === polyline;
		})[0].layer.getBounds());
	};
	
	// 缩放平移到当前标记
	Map.prototype.zoomAroundMarker = function () {
		if (marker)
			map.panTo(marker.getLatLng());
	};
	
	/**
	 * 在指定位置显示标记
	 */
	Map.prototype.showMarker = function (lat, lng) {
		if (!marker) {
			marker = L.marker([lat, lng], {
				icon: L.divIcon({
					iconSize: L.point(8, 8)
				})
			});
			map.addLayer(marker);
		} else {
			marker.setLatLng([lat, lng]);
		}
	};
	
	// 获取当前缩放级别
	Map.prototype.getZoom = function () {
		return map.getZoom();
	};
	
	// 添加事件处理方法
	Map.prototype.on = function (type, fn) {
		if (listeners[type])
			listeners[type].push(fn);
	};
	
	// 触发事件
	var fire = function (type, e) {
		if (listeners[type])
			listeners[type].forEach(function (value) {
				if (typeof value === "function")
					value.call(this, e);
			});
	};
	
	return Map;
})();

/*
 * Class Pano
 */
var Pano = (function () {
	// innerContainer 所在的 HTMLElement
	var panoContainer;
	// 放置全景图的 HTMLElement
	var innerContainer;
	// 上一次的 innerContainer
	var lastContainer;
	// 过渡 HTMLElement
	var loadingElement;
	// PhotoSphereViewer 实例
	var photoSphereViewer;
	// 事件处理方法集合
	var listeners = {
		"forward": [],
		"backward": []
	};
	
	// 构造函数
	// 参数 element 是渲染全景图的元素的 id
	var Pano = function (element) {
		panoContainer = document.getElementById(element);
		loadingElement = document.createElement("div");
		$(loadingElement).css({
			"background-color": "black",
			"position": "absolute",
			"top": "0",
			"bottom": "0",
			"left": "0",
			"right": "0",
			"opacity": "0",
			"z-index": 1
		});
	};
	
	// 渲染全景图
	// 参数 url 是图片的地址
	// 参数 hasForwardArrow 指定是否显示前进箭头
	// 参数 hasBackwardArrow 指定是否显示后退箭头
	Pano.prototype.render = function (url, hasForwardArrow, hasBackwardArrow) {
		// 创建容器
		lastContainer = innerContainer;
		innerContainer = document.createElement("div");
		$(innerContainer).css({
			"position": "absolute",
			"top": "0",
			"bottom": "0",
			"left": "0",
			"right": "0"
		});
		// 播放过渡动画
		$(panoContainer).prepend(loadingElement);
		$(loadingElement).fadeTo(500, 0.5);
		// 放上此次的全景图
		$(panoContainer).append(innerContainer);
		// 创建 PhotoSphereViewer 实例
		setTimeout(function() {
			photoSphereViewer = new PhotoSphereViewer({
				panorama: url,
				container: innerContainer,
				time_anim: false,
				navbar: false,
				tilt_up_map: 40,
				long_offset: Math.PI / 1080,
				lat_offset: Math.PI / 1080,
				usexmpdata: false,
				pano_size: {
					cropped_height_coef: 0.7
				},
				size: {
					height: "100%",
					width: "100%"
				},
				default_position: {
					long: photoSphereViewer ? photoSphereViewer.getPosition().longitude : Math.PI / 2 + Math.atan(20 / 100)
				},
				hasForwardArrow: hasForwardArrow,
				hasBackwardArrow: hasBackwardArrow,
				onforward: function (e) { fire("forward", e); },
				onbackward: function (e) { fire("backward", e); },
				onready: onReady
			});
		}, 500);
	};
	
	// 在 HTML 中显示全景图浏览器的 HTMLElement
	Pano.prototype.show = function () {
		$(panoContainer).removeClass("hide");
	};
	
	// 在 HTML 中隐藏全景图浏览器的 HTMLElement
	Pano.prototype.hide = function () {
		$(panoContainer).addClass("hide");
	};
	
	// 添加事件处理方法
	Pano.prototype.on = function (type, fn) {
		if (listeners[type])
			listeners[type].push(fn);
	};
	
	// 触发事件
	var fire = function (type, e) {
		if (listeners[type])
			listeners[type].forEach(function (value) {
				if (typeof value === "function")
					value.call(this, e);
			});
	};
	
	// 响应 PhotoSphereViewer 的 ready 事件
	var onReady = function (e) {
		// 删除上一次的全景图
		if (lastContainer)
			$(lastContainer).remove();
		// 移除过渡动画
		$(loadingElement).fadeOut(1000);
		setTimeout(function () { $(loadingElement).remove(); }, 1000);
	};
	
	return Pano;
})();

/**
 * 在多个点中寻找离指定点最近的点
 * @param {L.LatLng} point 是一个 L.LatLng 对象，表示指定点的坐标
 * @param {Object[]} points 是一个数组，表示多个点的坐标
 * @return {Object} 返回最近的点
 */
var closestPoint = function (point, points) {
	var minDistance = Number.POSITIVE_INFINITY;
	var minPoint = null;
	points.forEach(function (value) {
		var distance = point.distanceTo([value.latitude, value.longitude]);
		if (distance < minDistance) {
			minDistance = distance;
			minPoint = value;
		}
	});
	return minPoint;
};